package com.onec.service.im.service;


import com.onec.service.im.codec.ProtoDecode;
import com.onec.service.im.codec.ProtoEncode;
import com.onec.service.im.handler.LoginRequestHandler;
import com.onec.service.im.handler.ServiceExceptionHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class ChatService {

  @Value("${server.port}")
  private int port;
  // 通过nio方式来接收连接和处理连接
  private EventLoopGroup bg;
  private EventLoopGroup wg;

  // 启动引导器
  private ServerBootstrap b = new ServerBootstrap();

  @Autowired
  private LoginRequestHandler loginRequestHandler;
  @Autowired
  private ServiceExceptionHandler serviceExceptionHandler;


  public void run() {
    bg = new NioEventLoopGroup(1);
    wg = new NioEventLoopGroup();

    b.group(bg, wg);
    b.channel(NioServerSocketChannel.class);

    b.localAddress("", 8080);

    b.option(ChannelOption.SO_KEEPALIVE, true);
    b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

    // 配置子通道处理流程
    b.childHandler(new ChannelInitializer<SocketChannel>() {
      @Override
      protected void initChannel(SocketChannel sc) throws Exception {
        sc.pipeline().addLast("deCode", new ProtoDecode());
        sc.pipeline().addLast("enCode", new ProtoEncode());

        sc.pipeline().addLast("login", loginRequestHandler);
        sc.pipeline().addLast("exception", serviceExceptionHandler);
      }
    });

    ChannelFuture channelFuture = null;
    boolean isStart = false;
    while (!isStart) {
      try {
        channelFuture = b.bind().sync();
        log.info("服务启动成功：");
        isStart = true;

      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    // jvm 钩子函数 变比资源！
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
      @Override
      public void run() {
        wg.shutdownGracefully();
        bg.shutdownGracefully();
      }
    }));

    // 监听通道关闭事件
    ChannelFuture closeFuture = channelFuture.channel().closeFuture();
    try {
      channelFuture.sync();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      wg.shutdownGracefully();
      bg.shutdownGracefully();
    }
  }
}
